// Copyright (c) 2009 Hypirinha contributers
// This program is made available under the terms of the MIT License.
package org.hypirinha.html.codegen;

import org.w3c.dom.Document;
import org.w3c.dom.NodeList;

import javax.xml.xpath.XPath;
import javax.xml.xpath.XPathConstants;
import javax.xml.xpath.XPathExpressionException;
import java.util.ArrayList;
import java.util.List;
import java.util.Set;
import java.util.Map;
import java.util.HashMap;

public class ElementGenerator {

    public List<CompilationUnit> generate() {

        Document schema = new SchemaParser().parseSchema();

        Map<String, Element> elements = new HashMap<String, Element>();

        XPath xPath = XPathUtil.createXPath();
        try {
            NodeList nodes = (NodeList) xPath.evaluate("/xs:schema/xs:element", schema, XPathConstants.NODESET);

            for (int i = 0; i < nodes.getLength(); i++) {
                String name = xPath.evaluate("@name", nodes.item(i));
                elements.put(name, new Element(name));
            }

        } catch (XPathExpressionException e) {
            throw new RuntimeException(e);
        }

        for (String name : elements.keySet()) {
            Set<String> childNames = new ChildElementFinder(schema).findChildren(name);
            elements.get(name).addContentElementTypes(childNames);
            for (String childName : childNames) {
                elements.get(childName).addContainingElementType(name);
            }
        }

        ArrayList<CompilationUnit> classes = new ArrayList<CompilationUnit>();
        for (Element element : elements.values()) {
            classes.add(element.createElementInterface());
            classes.add(element.createContentInterface());
            classes.add(element.createElementImplementation());
        }
        classes.add(new ElementFactory(elements.keySet()).createImplementation());
        Text text = new Text();
        text.addContainingElementTypes(elements.keySet());
        classes.add(text.createTextClass());
        return classes;
    }

}
